﻿using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
using StoreDemo.Domain.Entities;
using StoreDemo.Domain.Services;
using StoreDemo.Web.Controllers;

namespace StoreDemo.Web.Test.Unit.Controllers
{
    [TestClass]
    public class ProductsControllerTests
    {
        [TestMethod]
        public void Index_ReturnsAllProductsFromTheProductsServce()
        {
            //Arrage
            IProductService productService = MockRepository.GenerateStub<IProductService>();
            IEnumerable<Product> products = new List<Product>();
            productService.Stub(x => x.GetAllProducts()).Return(products);

            //Act
            ProductsController productsController = new ProductsController(productService);
            ViewResult viewResult = productsController.Index();

            //Assert
            CollectionAssert.AreEqual((List<Product>) viewResult.Model, products.ToList());
        }

        [TestMethod]
        public void CreateHttpPost_AsksTheProductsServiceToSaveTheProduct()
        {
            //Arrange
            IProductService productService = MockRepository.GenerateStub<IProductService>();
            Product product = new Product();

            //Act
            ProductsController productsController = new ProductsController(productService);
            productsController.Create(product);

            //Assert
            productService.AssertWasCalled(x => x.Save(product));
        }

        [TestMethod]
        public void CreateHttpPost_RedirectsToTheIndexIfProductIsSaved()
        {
            //Arrange
            IProductService productService = MockRepository.GenerateStub<IProductService>();
            Product product = new Product();

            //Act
            ProductsController productsController = new ProductsController(productService);
            RedirectToRouteResult redirectToRouteResult = (RedirectToRouteResult) productsController.Create(product);

            //Assert
            Assert.AreEqual("Index", redirectToRouteResult.RouteValues["Action"]);
        }

        [TestMethod]
        public void CreateHttpPost_IfModelValidationFailsThenTheProductIsNotSaved()
        {
            //Arrange
            IProductService productsService = MockRepository.GenerateStub<IProductService>();
            Product product = new Product();

            //Act
            ProductsController productsController = new ProductsController(productsService);
            productsController.ModelState.AddModelError("TestError", "Test model validation error");
            productsController.Create(product);

            //Assert
            productsService.AssertWasNotCalled(x => x.Save(product));
        }

        [TestMethod]
        public void CreateHttpPost_IfModelValidationFailsThenTheFailingProductIsRetuned()
        {
            //Arrange
            IProductService productsService = MockRepository.GenerateStub<IProductService>();
            Product product = new Product();

            //Act
            ProductsController productsController = new ProductsController(productsService);
            productsController.ModelState.AddModelError("TestError", "Test model validation error");
            ViewResult viewResult = (ViewResult) productsController.Create(product);

            //Assert
            Assert.AreSame(product, viewResult.Model);
        }

        [TestMethod]
        public void Edit_ReturnsTheSpecifiedProduct()
        {
            //Arrange
            const int productId = 12020;

            IProductService productService = MockRepository.GenerateStub<IProductService>();
            Product expectedProduct = new Product();
            productService.Stub(x => x.Get(productId)).Return(expectedProduct);

            //Act
            ProductsController productsController = new ProductsController(productService);
            ViewResult viewResult = productsController.Edit(productId);

            //Assert
            Assert.AreSame(expectedProduct, viewResult.Model);
        }

        [TestMethod]
        public void EditHttpPost_AsksTheProductServiceToUpdateTheProduct()
        {
            //Arrange
            IProductService productService = MockRepository.GenerateStub<IProductService>();
            Product updatedProduct = new Product();

            //Act
            ProductsController productsController = new ProductsController(productService);
            productsController.Edit(updatedProduct);

            //Assert
            productService.AssertWasCalled(x => x.Update(updatedProduct));
        }

        [TestMethod]
        public void EditHttpPost_RedirectsToTheIndexOnSuccessfulUpdate()
        {
            //Arrange
            IProductService productService = MockRepository.GenerateStub<IProductService>();
            Product updatedProduct = new Product();

            //Act
            ProductsController productsController = new ProductsController(productService);
            RedirectToRouteResult redirectToRouteResult = (RedirectToRouteResult) productsController.Edit(updatedProduct);

            //Assert
            Assert.AreEqual("Index", redirectToRouteResult.RouteValues["Action"]);
        }

        [TestMethod]
        public void EditHttpPost_IfModelValidationFailsThenTheProductIsNotUpdated()
        {
            //Arrange
            IProductService productService = MockRepository.GenerateStub<IProductService>();
            Product updatedProduct = new Product();

            //Act
            ProductsController productsController = new ProductsController(productService);
            productsController.ModelState.AddModelError("TestError", "Test model validation error");
            productsController.Edit(updatedProduct);

            //Assert
            productService.AssertWasNotCalled(x => x.Update(updatedProduct));
        }

        [TestMethod]
        public void EditHttpPost_IfModelValidationFailsTheFailingProductIsReturned()
        {
            //Arrange
            IProductService productService = MockRepository.GenerateStub<IProductService>();
            Product updatedProduct = new Product();

            //Act
            ProductsController productsController = new ProductsController(productService);
            productsController.ModelState.AddModelError("TestError", "Test model validation error");
            ViewResult viewResult = (ViewResult) productsController.Edit(updatedProduct);

            //Assert
            Assert.AreSame(updatedProduct, viewResult.Model);
        }

        [TestMethod]
        public void DeleteHttpPost_AsksTheProductServiceToDeleteTheSpecifiedProduct()
        {
            //Arrange
            const int idOfProductToBedeleted = 3132;

            IProductService productService = MockRepository.GenerateStub<IProductService>();

            //Act
            ProductsController productsController = new ProductsController(productService);
            productsController.Delete(idOfProductToBedeleted);

            //Assert
            productService.AssertWasCalled(x => x.Delete(idOfProductToBedeleted));
        }

        [TestMethod]
        public void DeleteHttpPost_RedirectsToTheIndexAction()
        {
            IProductService productService = MockRepository.GenerateStub<IProductService>();

            //Act
            ProductsController productsController = new ProductsController(productService);
            RedirectToRouteResult redirectToRouteResult = productsController.Delete(1230832);

            //Assert
            Assert.AreEqual("Index", redirectToRouteResult.RouteValues["Action"]);
        }
    }
}